package com.intelligent.security;

import com.intelligent.entity.Permission;
import com.intelligent.service.PermissionRuleService;
import com.intelligent.service.UserService;
import com.intelligent.utils.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

/**
 * 动态鉴权拦截器：直接使用 t_permission 表中配置的 path/type/permission_code 作为规则
 */
@Component
public class AuthorizationInterceptor implements HandlerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(AuthorizationInterceptor.class);

    @Autowired
    private PermissionRuleService permissionRuleService;

    @Autowired
    private UserService userService;

    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        Object uidObj = request.getAttribute("CURRENT_USER_ID");
        if (uidObj == null) {
            return unauthorized(response, "未认证用户");
        }
        Long userId = Long.parseLong(String.valueOf(uidObj));

        String method = request.getMethod().toUpperCase(Locale.ROOT);
        String path = request.getRequestURI();

        List<Permission> rules = permissionRuleService.getApiRules();
        String requiredPermission = null;
        for (Permission rule : rules) {
            String ruleMethod = rule.getType();
            String rulePath = rule.getPath();
            if (rulePath == null || ruleMethod == null)
                continue;
            boolean methodMatch = "ALL".equalsIgnoreCase(ruleMethod) || method.equalsIgnoreCase(ruleMethod);
            if (!methodMatch)
                continue;
            if (pathMatcher.match(rulePath, path)) {
                requiredPermission = rule.getPermissionCode();
                break;
            }
        }

        if (requiredPermission == null || requiredPermission.isEmpty()) {
            // 未配置规则，默认放行（如需严格，可改为拦截）
            log.debug("[AUTHZ] No rule matched for {} {} -> pass", method, path);
            return true;
        }

        List<String> userPerms = userService.getPermissionsByUserId(userId);
        Set<String> normalized = new HashSet<>();
        if (userPerms != null) {
            for (String p : userPerms) {
                if (p != null)
                    normalized.add(normalize(p));
            }
        }
        String requiredNorm = normalize(requiredPermission);
        boolean allowed = normalized.contains(requiredNorm);
        log.debug("[AUTHZ] {} {} requires '{}'(norm='{}'), userPerms(norm)={} -> {}",
                method, path, requiredPermission, requiredNorm, normalized, allowed ? "ALLOW" : "DENY");

        if (allowed)
            return true;
        return forbidden(response, "无权限: " + requiredPermission);
    }

    private String normalize(String s) {
        // 统一为小写，并去掉所有非字母数字字符，这样 'user:view' 和 'userview' 也能匹配
        return s.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9]", "");
    }

    private boolean unauthorized(HttpServletResponse response, String msg) throws IOException {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.setContentType("application/json;charset=UTF-8");
        String body = Result.error(HttpStatus.UNAUTHORIZED.value(), msg).toString();
        response.getWriter().write(body);
        return false;
    }

    private boolean forbidden(HttpServletResponse response, String msg) throws IOException {
        response.setStatus(HttpStatus.FORBIDDEN.value());
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        response.setContentType("application/json;charset=UTF-8");
        String body = Result.error(HttpStatus.FORBIDDEN.value(), msg).toString();
        response.getWriter().write(body);
        return false;
    }
}
